package com.scau.os.controller;

import com.scau.os.course_manager.*;
import com.scau.os.course_manager.bean.PCB;
import com.scau.os.course_manager.bean.ProcessState;
import com.scau.os.course_manager.bean.ValueChangeListener;
import com.scau.os.extension.EventSystem;
import com.scau.os.extension.MyDelegate;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;

import java.net.URL;
import java.util.*;

public class CourseViewController implements Initializable {

    @FXML
    private Color x2111;

    @FXML
    private Color x21111;

    @FXML
    private Font x1111;

    @FXML
    private Font x111111;

    @FXML
    private Color x211;

    @FXML
    private Font x111;



    @FXML
    private Color x211111;

    @FXML
    private Color x2111111;



    @FXML
    private Color x21;

    @FXML
    private Font x11111;

    @FXML
    private Font x12;

    @FXML
    private Font x1;

    @FXML
    private Font x11;

    @FXML
    private Color x22;
    @FXML
    private Font x1111111;

    @FXML
    private Color x4;
    @FXML
    private Font x3;
    @FXML
    private Color x2;

    @FXML
    private ScrollPane blockQueue;
    @FXML
    private Label executeResultLabel;
    @FXML
    private ScrollPane readyQueue;
    @FXML
    private Label intermediateResultLabel;
    @FXML
    private Label runningCommandLabel;
    @FXML
    private Label runningProcessID;
    @FXML
    private Label systemClock;
    @FXML
    private Label relativeClock;
    @FXML
    public AnchorPane outAnchorPanel;
    @FXML
    private AnchorPane a2;

    @FXML
    private AnchorPane a3;

    @FXML
    private AnchorPane a4;

    @FXML
    private AnchorPane a1;
    private HashMap<String,Node> readyMap=new HashMap<String, Node>();
    private HashMap<String,Node> blockMap=new HashMap<String, Node>();

    //记得在窗口关闭之后注销事件
    public ValueChangeListener valueChangeListener;

    private static final double LABEL_HEIGHT=200;


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        register();
        init();
    }
    private void register(){
        EventSystem.instance.register(new MyDelegate("RunningPCBUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    runningProcessID.setText((String)data);
                });

            }
        }).UnRegisterWhenClose(this);
        EventSystem.instance.register(new MyDelegate("SystemClockUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    Integer i=(Integer) data;
                    systemClock.setText(i.toString());
                });

            }
        }).UnRegisterWhenClose(this);
        EventSystem.instance.register(new MyDelegate("RelativeClockUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    Integer i=(Integer) data;
                    relativeClock.setText(i.toString());
                });

            }
        }).UnRegisterWhenClose(this);
        EventSystem.instance.register(new MyDelegate("IntermediateResultUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    String s=(String)data;
                    intermediateResultLabel.setText(s);
                });
            }
        }).UnRegisterWhenClose(this);
        EventSystem.instance.register(new MyDelegate("RunningCommandUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    String s=(String) data;
                    runningCommandLabel.setText(s);
                });
            }
        }).UnRegisterWhenClose(this);
        EventSystem.instance.register(new MyDelegate("ExecuteResultUpdate") {
            @Override
            public void execute(Object data) {
                Platform.runLater(()->{
                    String s=(String)data;
                    executeResultLabel.setText(s);
                });
            }
        }).UnRegisterWhenClose(this);
    }
    private void addListener(List<PCB> pcbs){
        for (PCB p :
                pcbs) {
            p.addStateChangeListener(valueChangeListener);
        }
    }
    private void deleteListener(List<PCB> pcbs){
        for (PCB p :
                pcbs) {
            p.deleteStateChangeListener(valueChangeListener);
        }
    }
    public void unregister(){
        deleteListener(ProcessPool.getInstance().all);
    }
    private void init(){
        a1.prefHeightProperty().bind(outAnchorPanel.heightProperty());
        a1.prefWidthProperty().bind(outAnchorPanel.widthProperty().divide(4));
        a2.prefHeightProperty().bind(outAnchorPanel.heightProperty());
        a2.prefWidthProperty().bind(outAnchorPanel.widthProperty().divide(4));
        a3.prefHeightProperty().bind(outAnchorPanel.heightProperty());
        a3.prefWidthProperty().bind(outAnchorPanel.widthProperty().divide(4));
        a4.prefHeightProperty().bind(outAnchorPanel.heightProperty());
        a4.prefWidthProperty().bind(outAnchorPanel.widthProperty().divide(4));
        readyQueue.prefHeightProperty().bind(outAnchorPanel.heightProperty());
        blockQueue.prefHeightProperty().bind(outAnchorPanel.heightProperty());

        VBox ready=new VBox();
        VBox block=new VBox();
        readyQueue.setContent(ready);
        ready.prefHeightProperty().bind(readyQueue.heightProperty());
        ready.prefWidthProperty().bind(readyQueue.widthProperty());
        // 自适应高度
        readyQueue.setFitToHeight(true);

        blockQueue.setContent(block);
        block.prefHeightProperty().bind(blockQueue.heightProperty());
        block.prefWidthProperty().bind(blockQueue.widthProperty());
        // 自适应高度
        blockQueue.setFitToHeight(true);

        runningProcessID.setText(ProcessPool.getInstance().idle.processID);
        Font font=new Font(22);
        valueChangeListener=new ValueChangeListener() {

            @Override
            public void onChanged(ProcessState oldValue, ProcessState newValue, String processID) {
                Platform.runLater(()->{

                    if(oldValue==ProcessState.READY){
                        ready.getChildren().remove(readyMap.get(processID));
                        readyMap.remove(processID);
                    }

                    if(newValue==ProcessState.READY){
                        Label label=new Label(processID);
                        label.prefHeight(LABEL_HEIGHT);
                        label.prefWidthProperty().bind(ready.prefWidthProperty());
                        label.setFont(font);
                        readyMap.put(processID,label);
                        ready.getChildren().add(label);

                    }

                    if(oldValue==ProcessState.BLOCK){
                        block.getChildren().remove(blockMap.get(processID));
                        blockMap.remove(processID);
                    }

                    if(newValue==ProcessState.BLOCK){
                        Label label=new Label(processID);
                        label.setFont(font);
                        label.prefHeight(LABEL_HEIGHT);
                        label.prefWidthProperty().bind(block.prefWidthProperty());
                        blockMap.put(processID,label);
                        block.getChildren().add(label);

                    }

                });

            }
        };

        addListener(ProcessPool.getInstance().all);
        //初始化，把所有的阻塞队列和就绪队列和正在运行的进程ID加载进去
        //还要初始化map索引
        synchronized (ProcessPool.getInstance().ready){
            for (PCB p :
                    ProcessPool.getInstance().ready) {
                Label label=new Label(p.processID);
                label.setFont(font);
                label.prefHeight(LABEL_HEIGHT);
                label.prefWidthProperty().bind(ready.prefWidthProperty());
                readyMap.put(p.processID,label);
                ready.getChildren().add(label);
            }
        }
        synchronized (ProcessPool.getInstance().block){
            for (PCB p :
                    ProcessPool.getInstance().block) {
                Label label=new Label(p.processID);
                label.setFont(font);
                label.prefHeight(LABEL_HEIGHT);
                label.prefWidthProperty().bind(block.prefWidthProperty());
                blockMap.put(p.processID,label);
                block.getChildren().add(label);
            }
        }
    }
}
